import { Button } from 'antd'
import { useState, useCallback, PureComponent, memo } from 'react'
import styled from 'styled-components'

// 一点破样式
const DemoStyle = styled.div`
    box-sizing: border-box;
    margin: 20px auto;
    padding: 20px;
    width: 300px;
    border: 1px solid #DDD;

    p{
        font-size: 18px;
        line-height: 40px;
    }

    .ant-btn{
        margin-right: 10px;
    }
`

/* class Child extends PureComponent {
    render() {
        console.log('子组件渲染/更新')
        return <div>
            我是子组件
        </div>
    }
} */

// 函数组件中，如果想对新老属性做比较，从而控制视图更新或者不更新，需要使用 React.memo 方法
const Child = memo(function Child(props) {
    console.log('子组件渲染/更新')
    return <div>
        我是子组件
    </div>
})


export default function Demo() {
    console.log('父组件渲染/更新')
    let [x, setX] = useState(10)

    /* 
    父组件每一次更新，都是把函数重新执行，产生一个新的闭包；闭包中的handle方法也会重新创建一个新的函数(新的堆内存)；这样每一次传递给 Child 的属性值，都是新的堆内存地址；所以不论子组件继承的是 PureComponent 还是 Component ，每一次更新，其接收的属性值都是发生变化的，所以子组件也要更新！
    ---
    但是函数组件本应如此，只有每一次更新都创建新的函数出来，这样在函数中用的状态，才是当前闭包中的信息！
    如果每次更新，handle方法依然是闭包一中的handle，那么在handle中，我们使用的状态，也依然是闭包1中的！
    */
    // const handle = () => { }

    /* 
    useCallback：可以确保每一次组件更新，都拿到第一次创建函数的堆内存地址（也就是组件更新的时候，不会重新创建新的函数了，一直使用第一次创建的函数） 
      useCallback(callback,[]) 只有第一次渲染创建新的函数，后期组件每次更新，获取的都是第一次创建的函数
        + 使用这种方式，会存在一个很严重的问题：函数中获取的状态值，也永远是闭包1中的
        + 但是也会带来一种优化：如果我们把函数作为属性传递给子组件「前提：子组件内部也对新老属性做了比较，如果发现一样，则不允许更新（类组件继承PureComponent或者自己设置shouldComponentUpdate；函数组件基于React.memo处理即可）」，因为每一次获取的函数都是一致的，导致传递的属性也是一样的，则子组件不会再更新了！
      useCallback(callback,[x]) 只有第一次渲染和x状态更新，才会重新创建新的函数
      useCallback(callback) 和不设置useCallback一样，每一次渲染都会创建新的函数
    */
    const handle = useCallback(() => { }, [])

    return <DemoStyle>
        <Child handle={handle} />
        <p>{x}</p>
        <Button type="primary" size="small" onClick={() => setX(x + 1)}>修改X</Button>
    </DemoStyle>
}